[MySQL]基础
数据模型
数据模型与现实世界中的模型一样,是对现实世界数据特征的一种抽象。比如一个学生的特征暴扣姓名、年轻、学号等,这些特征被称为属性,属性具有以下特点:
- 属性不可再分。
- 一个实体的属性可以有很多歌。
- 用于唯一区分不同实体的属性,称为key,比如每个学生的学号都是不一样的。
属性取值可以有一定的约束,比如性别只能是男或女。
属性追安可以具有一定的联系:
- 一个老师教很多学生就是一对多(1:n)
- 学生与学好唯一对应(1:1)
- 一个老师可以教多个学生,一个学生也可以有多个老师,多对多。(n:m)
数据库的规范化
第一范式(1NF)
第一范式是指数据库的每一列都是不可分割的基本数据项,而下面这样的就存在可分割的情况:
- 学生(姓名,电话号码)
电话号码实际上包括了家用座机号码和移动电话,因此它可以拆分为:
- 学生(姓名,座机号码,手机号码)
满足第一范式是关系数据库最基本的要求。
第二范式(2NF)
第二范式要求表中必须存在逐渐,且其他属性必须完全依赖于主键,比如:
- 学生(学号,姓名,性别)
学号是每个学生的唯一标识,每个学生都有着不同的学号,因此次表中存在一个主键,并且每个学生的所有属性都依赖于学号,学号发生改变表示学生发生改变,姓名和性别都会因此改变,所以此表满足第二范式。
第三范式(3NF)
再满足第二范式的情况下,所有的属性都不传递依赖于主键,满足第三范式。
- 学生借书情况(借阅编号,学生编号,书籍编号,书籍名称,书籍作者)
实际上书籍编号依赖于借阅编号,而书籍名称和书籍作者依赖于书籍编号,因此存在传递依赖的情况,我们可以将书籍信息进行单独拆分为另一张表:
- 学生借书情况(借阅编号,学生编号,书籍编号)
- 书籍(书籍编号,书籍名称,书籍作者)
这样就消除了传递依赖。从而满足第三范式
BCNF
BCNF作为第三范式的补充。
- 假设仓库管理关系表为StorehouseManage(仓库D,存储物品ID,管理员ID,数量)。
- 且有一个管理员只在一个仓库工作;
- 一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:
- (仓库ID,存储物品ID) -> (管理员ID,数量)
- (管理员ID,存储物品ID) -> (仓库ID,数量)
所以,(仓库ID,存储物品ID)和(管理员ID,存储物品ID)都是StorehouseManage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是由于存在如下决定关系:
(仓库ID) -> (管理员ID)
(管理员ID) -> (仓库ID)
即粗在关键字段决定关键字短的情况,如果修改管理员ID,那么就必须逐一进行修改,所以其不符合BCNF范式。
SQL语句
主要分为四类:
- 数据查询语言(Data Query Language,DQL) 基本结构是由SELECT子句,FROM子句,WHERE子句组成的查询块
- 数据操纵语言(Data Manipulation Language,DML)是SQL语言中,负责对数据库对象运行数据访问工作的指令集,以INSERT、UPDATE、DELETE三种指令为核心,分别代表插入、更新与删除,是开发以数据为中心的应用程席必定会使用到的指令。
- 数据库定义语言DDL(Data Definition Language),是用于描述数据库中要存储的现实世界实体的语言。
- DCL(Data ControlLanguage) 是数据库控制语言。是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句。在默认状态下,只有sysadmin,dbcreatordb owner或db securityadmin等人员才有权力执行DCL.
我们平时所说的CRUD其实就是增删改查 (Create/Retrieve/Update/Delete)
数据库定义语言(DDL)
- 通过create database创建一个数据库:
1
create database 数据库名
- 创建时设置编码格式来支持中文:
1
CREATE DATABASE IF NOT EXISTS 数据库名 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
- 通过drop database 删除数据库
1
drop database 数据库名
列级约束条件
- NOT NULL:指定列不能为空
- UNIQUE :指定列中的值必须是唯一的,不能重复
- 主键:指定列表为主键,可以唯一标识每一行数据。不能为NULL,且唯一
- 外健:可以关联到另一张表中的主键列。外健列的值必须存在于关联表的主键列中,否则会出现出发关联失败的错误。
- CHECK检查: 指定列中的值必须满足指定条件。常见的条件包括大小、范围、正则表达式。(MySQL不支持)
- 默认:指定列的默认值。
表的约束条件
主键、外键、唯一、检查
数据库查询语言(DQL)
聚集函数
一般用于作统计,包括:
- count([distinct]*)统计所有的行数(distinct表示去重再统计,下同)。
- count([distinct]列名)统计某列的值的种类的总和.
- sum([distinct]列名)求一列的和。(注意必须是数字类型的)
- avg([distinct]列名)求一列的平均值。(注意必须是数字类型的)
- max([distinct]列名)求一列的最小值。
- min([distinct]列名)求一列的最大值。
1 | SELECT count(distinct 列名) FROM 表名 WHERE 条件 |
分组和分页查询
通过group by来对查询结果进行分组,它需要结合聚合函数一起使用:
1 | SELECT sum(*) FROM 表名 WHERE 条件 GROUP BY 列名 |

通过having来限制条件
1
2SELECT sum(*) FROM 表名 WHERE 条件 GROUP BY 列名 HAVING 约束条件
SELECT COUNT(*), sex FROM student GROUP BY sex HAVING sex = '男'通过limit来限制查询数量
- 只查询前三条
1
2SELECT * FROM 表名 LIMIT 数量
SELECT *FROM student LIMIT 3 - 分页一页显示2个,查第一页
1
SELECT * FROM 表名 LIMIT 起始位置,数量
第二页1
SELECT *FROM student LIMIT 0,2
1
SELECT *FROM student LIMIT 1,2
多表查询
多表查询是同时查询的两个或两个以上的表,多表查询会提通过连接转换为单表查询。
1
2SELECT * FROM 表1, 表2
SELECT *FROM student, teacher直接这样查询会得到两张表的笛卡尔积,也就是每一项数据和另一张表的每一项数据都结合一次,会产生庞大的数据
1
2SELECT * FROM 表1, 表2 WHERE 条件
SELECT *FROM student, teacher WHERE sid = 1
这样,只会从笛卡尔积的结果中得到满足条件的数据。
自身连接查询
自身连接,就是将表本身和表进行笛卡尔积计算,得到结果,但由于表名相同,因此需要先起一个别名:
1 | SELECT * FROM 表名 别名1, 表名 别名2 |
- 其实自身连接查询和前面的是一样的,只是连接对象变成自己和自己了。
外链接查询
- 专门用于联合查询情景的。
- 比如现在有一个存储所有用户的表,还有一张用户详细信息的表,我希望将这两张表结合到一起来查看完整的数据,我们就可以通过使用外连接来进行查询。
- 外连接有三种方式:
- 通过使用inner join进行内连接,只会返回两个表满足条件的交集部分:
1
SELECT * FROM student INNER JOIN teach on student.sid = teach.sid
- left join进行左连接,不仅会返回两个表满足条件的交集部分,也会返回左边表中的全部数据,而在右表中缺失的数据会使用null来代替(右连接同理):
1
SELECT *FROM student LEFT JOIN teach on student.sid = teach.sid
连续左连接1
2SELECT *FROM student LEFT JOIN teach on student.sid = teach.sid
LEFT JOIN teacher on teach.tid = teacher.tid1
2SELECT *FROM student LEFT JOIN teach on student.sid = teach.sid
LEFT JOIN teacher on teach.tid = teacher.tid WHERE teacher.name = '张三'
- 通过使用inner join进行内连接,只会返回两个表满足条件的交集部分:
嵌套查询
- 我们可以将查询的结果作为另一个查询的条件,比如:
查找张三教的学生1
2SELECT * FROM 表名 WHERE 列名 = (SELECT 列名 FROM 表名 WHERE 条件)
SELECT *FROM student WHERE sid in (SELECT sid FROM teach WHERE tid = (SELECT tid from teacher WHERE name = '张三'))
联查
1 | SELECT FROM student s LEFT JOIN teach t on s.sid = t.sid WHERE tid = (SELECT tid FROM teacher WHERE name = '张三') |
视图
- 视图本质就是一个查询结果,不过我们每次都可以通过打开视图来按照我们想要的样子查看数据。
- 既然视图的本质就是一个查询结果,那么它本身就是一个虚表,并不是真实存在的,数据实际上还是存放在原来的表中。
- 可以通过create view来创建视图
1
2CREATE VIEW 视图名称(列名) as 子查询语句 [WITH CHECK OPTION];
CREATE VIEW test as SELECT * FROM student WHERE sex = '男'
- 创建后,我们就可以使用select语句来直接查询视图上的数据了,因此,还能在视图的基础上,导出其他的视图。
1
SELECT *FROM test
1
UPDATE test set name = '小蓝' WHERE sid = 1
1 | CREATE VIEW test as SELECT * FROM student WHERE sex = ‘男’ WITH CHECK OPTION |
- WITH CHECK OPTION是指当创建后,如果更新视图中的数据,是否要满足子查询中的条件表达式,不满足将无法插入.
1
UPDATE test SET sex = '女' WHERE sid = 1
- 无法更改,报错:1369 - CHECK OPTION failed ‘learn.test’。即限定条件是sex=男,不能更改这个限定数据变成其他的,改成男的可以。
若视图是由两个及以上基本表导出的,则此试图不允许更新。
- 创建两个表的视图:
1
CREATE VIEW test as SELECT s.sid sid, name ,sex ,tid FROM student s LEFT JOIN teach t on s.sid = t.sid
- 不能使用 *,因为两张表都有sid
- 创建两个表的视图:
若视图的字段来自字段表达式或常数,则不允许对此视图执行INSERT和UPDATE操作,但允许执行DELETE操作。
- 若视图的字段来自集函数,则此视图不允许更新。
- 若视图定义中含有GROUP BY子句,则此视图不允许更新。
- 若视图定义中含有DISTINCT短语,则此视图不允许更新。
- 若视图定义中有嵌套查询,并且内层查询的FROM子句中涉及的表也是导出该视图的基本表,则此视图不允许更新。例如将成绩在平均成绩之上的元组定义成一个视图GOOD_SC: CREATE VIEW GOOD_SC AS SELECT Sno, Cno, Grade FROM SC WHERE Grade > (SELECT AVG(Grade) FROM SC); 导出视图GOOD_SC的基本表是SC,内层查询中涉及的表也是SC,所以视图GOOD_SC是不允许更新的。
- 一个不允许更新的视图上定义的视图也不允许更新。
索引
- 在数据量非常庞大时,通过创建索引,来提高我们的查询效率。
- 就像Hash一样,他能快速地定位到元素存放的位置。
1
2
3
4
5-- 创建索引
CREATE INDEX 索引名称 ON 表名 (列名)
CREATE INDEX i ON student(name)
-- 查看表中的索引
show INDEX FROM student
单列索引
单列索引只针对某一列数据创建索引,单列索引有以下几种类型:
- NORMAL:普通索引,完完全全相当于一本书的目录。
- UNIQUE:唯一索引,一旦建立,那么整个列中将不允许出现重复数据。每个表的主键列,都有一个特殊的唯一索引,叫做Primary Key,它不仅仅要求不允许出现重复,还要求不能为NULL,它还可以自动递增。每张表可以有多个唯一索引,但是只能有一个Primary索引。
- SPATIAL:空间索引,对空间数据类型的字段建立的索引,MYSQL中的空间索引有四种。
- FULLTEXT:全文索引,它是模糊匹配的一种更好的解决方案,它的效率比使用like更高,并且还支持多种匹配方式,灵活性也更加强大,只有字段的数据类型为char、varchar、text及其系列才可以建立全文索引。
我们来看看如何使用全文索引,首先创建一张用于测试全文索引的表:
1 | CREATE TABLE articles ( |

使用全文索引进行模糊匹配
1
SELECT *FROM articles WHERE MATCH(body) AGAINST ('database')
match中就是必须是哪些字段,against中定义需要模糊匹配的字符。
- 我们用作查找的字符串实际上是被分词之后的结果。
- 如果进行模糊匹配的不是一个词语,那么会查找失败,但是它的效率远高于以下这种写法:
1
SELECT * FROM articles WHERE body like '%database%';
聚簇索引和非聚簇索引
- 聚簇索引:索引和数据存放在一起,叶子节点保留数据行。
- 非聚簇索引:索引和数据分开存放,叶子节点存放的是指向数据行的地址。
组合索引
- 组合索引实际上就是将多行捆绑在一起,作为一个索引,同样支持以上几种索引类型。
- 注意组合索引进行匹配时,遵循最左原则。
- 最左原则:只有从索引的最左侧列开始一次查询,索引才会被使用。
- 例子:假设有一个联合索引(a,b,c)分别代表不同的列。如果查询条件时a=1,b=2,c=3,那么索引可以被利用。如果时b=2,c=3就无法被利用,因为查询条件中没有使用索引最左侧的列a。
- 唯一索引时只要有一个数据不一样就可以插入。
索引失效
- 1.遵守最左原则。
- 2.不在索引列上做任何操作(列入计算、函数、类型转换)
- 3.使用(!= 或 <>)的时候无法使用索引。
- LIKE和%通配符也无法使用索引。
- Like和%要扫描整个字符串列,并进行逐个比较,可能导致索引失效,从而强制MySQL执行全表扫描。
索引的底层原理
- 索引是存储在硬盘上的,跟我们之前使用的HashMap之类的不同,它们都是在内存中的,但是硬盘的读取速度远小于内存的速度,每一次IO操作都会耗费大量的时间。
- 我们也不可能把整个磁盘上的索引全部导入内存,因此我们需要考虑尽可能多的减少IO次数,索引的实现可以依靠两种数据结构,一种是我们在JavaSE阶段已经学习过的Hash表,还有一种就是B-Tree。
Hash
通过对Key进行散列值计算,我们可以直接得到对应数据的存放位置,它的查询效率能够达到O(1),但是它也存在一定的缺陷:
- Hash索引仅仅能满足“=”,“in”查询条件,不能使用范围查询。
- Hash碰撞问题。
- 不同用部分索引健来搜索,因为组合索引在计算哈希值时时一起计算的。
B+
- 有n棵子树的结点中含有n个健值。
- 所有的键值信息只在叶子节点中包含,非叶子节点仅仅保存节点的最小值(或最大值),和指向叶子节点的指针。
- 所有的叶子节点都有一个根据大小顺序只想下一个叶子节点的指针Q,本质上数据就是一个链表。
这样,读取IO的时间相比BTree就减少了很多,并且查询任何键值信息都需要完整地走到叶子节点,保证了查询的IO读取次数一致。因此MySQL默认选择B+Tree作为索引的存储数据结构。
这是MyISAM存储引擎下的B+Tree实现:
这是InnoDB存储引擎下的B+Tree实现:
区别:
- 主键:InnoDB直接存数据,MyISAM存的是地址。数据本身就是索引的一部分(所以这里建议主键使用自增)。
- 不是主键:最后存的是主键ID。(因此InnoDB必须有主键,若没有也会自动查找替代)。
事务
- 当我们要进行的操作非常多时,比如要依次删除很多个表的数据,我们就需要大量的SQL语句来完成。
- 这些数据库操作语句就可以构成一个事务。
- 只有Innodb引擎支持事务。
事务的特性
- 原子性:
- 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
- 事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:
- 在事务开始之前和结束之后,数据库的完整性没有被破坏。
- 这表示写入的资料必须完全符合所有预设规则,包括资料的精确度,串联性以及后续数据库可以自发性地完成预定的工作。
- 隔离性:
- 数据库运去多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行由于交叉执行导致数据的不一致。
- 事务隔离分为不同级别,包括未提交,读提交,可重复读和串行化。
- 持久性:事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。
锁机制
在MySQL中,很容易出现多线程同时操作表中数据的情况,如果要避免潜在的并发问题,那么我们就可以使用事务隔离机制来处理,就用到了锁机制。
隔离级别包括:
- 读未提交:能够读取到其他事务中未提交的内容,存在脏读问题。
- 脏读:假设有两个事务T1和T2,T1在执行的过程中,读取到了T2未提交的数据,这时如果T2回滚了,那么T1读取到的数据是不一致的。
- 读已提交:只能读取到其他事务已经提交的内容,避免了脏读的问题,但存在不可重复读的问题。
- 不可重复读问题:在同一个事务中,多次读取同一行数据时,得到的结果不同。这时因为在两次读取之间,另一个事务修改了这一行的数据,导致了第一次读取和第二次读取的结果不同。
- 可重复读:在读取某行后不允许其他事务操作此行,直到事务结束,但是依然存在幻读问题。
- 幻读:在一个事务中多次执行同一个查询,但得到结果却不同。这是因为在两次查询之间,有另一个数据提交了一些新的数据,导致查询结果发生了变化。可重复读只限制了update,但未限制insert。
- 串行读:一个事务的开始必须等待另一个事务的完成。
在RR级别下,MySQL在一定程度上解决了幻读问题:
- 在快照读(不加锁)读情况下,mysql通过mvcc来避免幻读。
- 在当前读(加锁)读情况下,mysql通过next-key来避免幻读。
MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
读锁和写锁
从对数据的操作类型上来说,锁分为读锁和写锁:
- 读锁:也叫共享锁,当一个事务添加了读锁后,其他的事务也可以添加读锁或是读取数据,但是不能进行写操作,只能等到所有的读锁全部释放。
- 写锁:也叫排他锁,当一个书屋添加了写锁后,其他事务不能读也不能写也不能添加任何锁,只能等待当前事务释放锁。
全局锁、表锁和行锁
从锁的作用范围上划分,分为全局锁、表锁和行锁:
- 全局锁:作用于全局,整个数据库的所有操作全部受到锁限制。
- 表锁:作用于整个表,所有对表的操作都会受到锁的下肢。
- 行锁:作用于表中的某一行,只会通过锁限制对某一行的操作。(仅InnoDB支持)
全局锁
我们首先来看全局锁,它作用于整个数据库,我们可以使用以下命令来开启读全局锁:
1 | flush tables with read lock; |
开启后,整个数据库被上读锁,我们只能去读数据,但是不允许写数据。(包括更新、插入、删除等)一旦执行写操作,会被阻塞,直到锁被释放,我们可以使用以下命令来解锁:
1
unlock tables;
除了手动释放锁之外,当我们的会话结束后,锁也会被自动释放。
表锁
- 表锁作用于某一张表,也是MyISAM和InnoDB存储引擎支持的方式,我们可以使用以下命令来为表添加锁:
1
lock table 表名称 read/write;
- 在我们为表添加写锁后,我们发现其他地方是无法访问此表的,一律都被阻塞。
行锁
- 表锁的作用范围太广了,如果我们仅仅只是对某一行进行操作,那么大可不必对整个表进行加锁,因此InnoDB支持了行锁,我们可以使用以下命令来对某一行进行加锁:
1
2
3
4-- 添加读锁(共享锁)
select * from ... lock in share mode;
-- 添加写锁(排他锁)
select * from ... for update; - 使用InnoDB的情况下,在执行更新、删除、插入操作时,数据库也会自动为所设计的行添加写锁(排他锁),直到事务提交时,才会释放锁。
- 执行普通的查询操作时,不会添加任何锁。
在使用MyISAM的情况下,在执行更新、删除、插入操作时,数据库会对设计的表添加写锁,在执行查询操作时,数据库会对设计的表添加读锁。
如果不使用ID进行选择,行锁将发生变化(行锁升级):
其他人的信息也无法进行修改。select * from student where name = '小明' lock in share mode;
- 因为没有索引,他不知道SQL语句的是哪一行,锁会升级成类似于表锁。
- 添加索引就可以了。
行锁需要索引。
记录锁、间隙锁和临健锁
行锁可以继续分为多个类型
记录锁
(Record Locks)记录锁。
- 仅仅锁住索引记录的一行。
- Record Locks锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么innodb会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。
- 当一条sql没有走任何索引时,那么将会在每一条聚合索引后面加写锁,这个类似于表锁,但在原理上和表锁不同。
间隙锁
- (Gap Locks)仅仅锁住一个索引区间(开区间,不包括双端端点)。
- 在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括索引记录本身。
- 比如在 1、2中,间隙锁的可能值有 (-∞, 1),(1, 2),(2, +∞),间隙锁可用于防止幻读,保证索引间的不会被插入数据。
临健锁
- (Next-Key Locks)Record lock + Gap lock,左开右闭区间。
- 默认情况下,InnoDB正是使用Next-key Locks来锁定记录(如select … for update语句)它还会根据场景进行灵活变换:
- 假设数据库有10条数据,事务中修改第100条,查询不到,变成间隙锁,此时锁(10, +∞)数据,10和10之前的还可以修改,但不可插入新数据。
乐观锁与悲观锁
- 乐观锁:是一种基于版本号(或时间戳)的并发控制策略。
- 假设数据在一般情况下不会发生冲突,因此对数据的读取和修改操作并不加锁。
- 而是在数据更新的时候,对数据版本进行比对,如果版本号不一致,则说明数据依据被其他事务修改过,此时会回滚事务,重新读取数据进行修改。
- 适用于多读少写的场景,可以提高并发性能。
- 悲观锁:是一种基于锁的并发控制策略:
- 假设数据在一般情况下可能发生冲突,因此在进行数据读取和修改操作时,会先对数据进行加锁。
- 其他事务此时无法对该数据进行操作,直到锁被释放。
- 适用于多写少读的场景,可以保证数据的一致性。
MVCC
是一种多版本并发控制技术,用于实现数据库系统的并发控制和事务隔离。
- 基于乐观锁的思想,通过在数据行中保存多个版本的数据,使得每个数据在读取数据的时候都可以读取到一个对应版本的数据,从而避免了数据的冲突和并发反问的问题。
- 在MVCC中,每个事务可以读取到自己开始之前提交的数据版本,但是无法读取到其他书屋还未提交的数据版本。
在MySQL中,MVCC主要通过以下两种方式实现:
- Undo日志:
- 在更新操作时,会先记录原来的数据,称为Undo日志。
- 当有事务需要读取数据时,MySQL会根据事务的隔离级别,在日志中找到对应的版本数据,并将其返回给事务进行操作。
- Read View:
- 事务在执行过程中维护的一个数据视图,包含了事务开始之前已经提交的所有数据版本。
- 当事务需要读取数据时,会根据事务的隔离级别,生成一个ReadView,并将其作为参数传递给存储引擎
- 读取数据时至返回符合ReadView条件的数据版本,从而实现了MVCC的效果。
日志系统
日志可以保证数据的一致性和可靠性,并提供数据恢复和复制功能。
InnoDB存储引擎提供了多种日志,包括重做日志(Redo Log)、回滚日志(Undo Log)、二进制日志等。
错误日志:
- 记录MySQL服务器的所有错误和警告消息。
- 包括启动、关闭、运行时等错误。
查询日志
- 记录所有执行的查询语句。
- 包括查询语句的文本、执行时间、返回行数等信息。
慢查询日志
- 记录执行时间超过指定阈值的查询语句。
- 通常用于找出需要优化和改进的查询。
二进制日志
- 用于复制和恢复数据。
- 在主从复制场景下,主服务器将数据修改操作写入二进制日志,从服务器读取二进制日志并执行相应操作以保证数据同步。
- 在数据恢复场景下,通过重放二进制日志可以将数据恢复到特定的时间点货状态。
事务日志
- 记录每个事务的更改操作,包括插入、更新、删除等操作。
- 用于实现ACID事务的特性,确保数据库数据的一致性。
- Redo Log(重做日志):记录了在事务提交之前对数据库的更改操作。当系统崩溃时可以用来恢复数据库的修改操作。
- Undo Log(撤销日志):记录了事务进行的所有修改操作和逆操作,当一个事务需要回滚时,可以通次日志将数据恢复到修改前的状态。MVCC功能使用次日志实现。
慢启动日志:
- 记录MySQL服务器启动时的详细信息。
- 包括各个组件的启动过状态、配置参数等。
通用日志
- 记录MySQL服务器的运行状态信息。
- 包括连接信息、状态变化等。
存储引擎
- MyISAM:MySQL5.5之前的默认存储引擎,在插入和查询的情况下性能很高,但是它不支持事务,只能添加表级锁。
- InnoDB:MySQL5.5之后的默认存储引擎,它支持ACID事务、行级锁、外健,但是性能比不过MyISAM,更加消耗资源。
- Memory:数据都存放在内存中,数据库重启或发生崩溃,表中的数据将全部丢失。
页偏移过大时怎么优化
如果页偏移过大,会导致查询性能变差,因为数据库需要扫描大量数据才能找到目标数据。
可以采取以下措施优化:
- 设置每页最大查询数量。
- 使用索引。
- 使用缓存。